Bring libusb sources inline for Mac to avoid binary compat horrors, ease
authorrobertl <robertl>
Wed, 13 Aug 2008 16:54:40 +0000 (16:54 +0000)
committerrobertl <robertl>
Wed, 13 Aug 2008 16:54:40 +0000 (16:54 +0000)
building source.

configure
configure.in
mac/libusb/README [new file with mode: 0644]
mac/libusb/darwin.c [new file with mode: 0644]
mac/libusb/descriptors.c [new file with mode: 0644]
mac/libusb/error.c [new file with mode: 0644]
mac/libusb/error.h [new file with mode: 0644]
mac/libusb/usb.c [new file with mode: 0644]
mac/libusb/usb.h [new file with mode: 0644]
mac/libusb/usbi.h [new file with mode: 0644]

index 40d34106f04a681a785a9b28d6628292acee64f9..426b8b87b079626b6c658e48fae01044d4575ef9 100755 (executable)
--- a/configure
+++ b/configure
@@ -4177,6 +4177,20 @@ echo "${ECHO_T}USB skipped" >&6; }
                USB_LIBS=-lsetupapi
        fi
        ;;
+    *-*-darwin*)
+      GBSER=gbser_posix.o
+      OSJEEPS="jeeps/gpslibusb.o \
+      mac/libusb/darwin.o \
+      mac/libusb/descriptors.o \
+      mac/libusb/error.o \
+      mac/libusb/usb.o "
+      USB_LIBS="-framework  IOKit -framework CoreFoundation"
+      cat >>confdefs.h <<\_ACEOF
+#define HAVE_LIBUSB 1
+_ACEOF
+
+      CFLAGS="$CFLAGS -Imac/libusb/"
+      ;;
     *)
        GBSER=gbser_posix.o
        { echo "$as_me:$LINENO: checking for libusb" >&5
@@ -4303,23 +4317,7 @@ _ACEOF
 
 fi
 
-               # Override libusb for Darwin to reduce external
-               # runtime requirement.
-               case "$target" in
-               *-*-darwin*)
-                 if test "x$ac_cv_lib_usb_usb_interrupt_read" = "xyes" ; then
-                       USB_LIBS="`libusb-config --prefix`/lib/libusb.a -framework  IOKit -framework CoreFoundation"
-                       LDFLAGS=$OLDFLAGS
-                       CDFLAGS=$OCDFLAGS
-                       OSJEEPS=jeeps/gpslibusb.o
-                   else
-                       OSJEEPS=jeeps/gpsusbstub.o
-                 fi
-                 ;;
-               *)
-                 OSJEEPS=jeeps/gpslibusb.o
-                 ;;
-               esac
+               OSJEEPS=jeeps/gpslibusb.o
                CFLAGS="$OCFLAGS"
        #       LIBS="$LIBS `libusb-config --libs`"
            else
index 19edc2ffa53f92f120c659cbb1ca693f823cee92..d2cfb62c316d2124f9c322fb3575df5748518aae 100644 (file)
@@ -159,6 +159,17 @@ case "$target" in
                USB_LIBS=-lsetupapi
        fi
        ;;
+    *-*-darwin*)
+      GBSER=gbser_posix.o
+      OSJEEPS="jeeps/gpslibusb.o \
+      mac/libusb/darwin.o \
+      mac/libusb/descriptors.o \
+      mac/libusb/error.o \
+      mac/libusb/usb.o "
+      USB_LIBS="-framework  IOKit -framework CoreFoundation"
+      AC_DEFINE(HAVE_LIBUSB, 1)
+      CFLAGS="$CFLAGS -Imac/libusb/"
+      ;;
     *)
        GBSER=gbser_posix.o
        AC_MSG_CHECKING(for libusb)
@@ -179,23 +190,7 @@ case "$target" in
                        [USB_LIBS="`libusb-config --libs`"]
 #                      ,[AC_MSG_ERROR([libusb >= 0.1.8 is needed])]
                        )
-               # Override libusb for Darwin to reduce external 
-               # runtime requirement.
-               case "$target" in
-               *-*-darwin*)
-                 if test "x$ac_cv_lib_usb_usb_interrupt_read" = "xyes" ; then
-                       USB_LIBS="`libusb-config --prefix`/lib/libusb.a -framework  IOKit -framework CoreFoundation"
-                       LDFLAGS=$OLDFLAGS
-                       CDFLAGS=$OCDFLAGS
-                       OSJEEPS=jeeps/gpslibusb.o
-                   else
-                       OSJEEPS=jeeps/gpsusbstub.o
-                 fi
-                 ;;
-               *)
-                 OSJEEPS=jeeps/gpslibusb.o
-                 ;;
-               esac
+               OSJEEPS=jeeps/gpslibusb.o
                CFLAGS="$OCFLAGS"
        #       LIBS="$LIBS `libusb-config --libs`"
            else
diff --git a/mac/libusb/README b/mac/libusb/README
new file mode 100644 (file)
index 0000000..6f1b72a
--- /dev/null
@@ -0,0 +1,13 @@
+This is libusb-0.1.12  with an updated darwin.c that lets USB Garmins
+work with 10.4.10 and later.  Since we have such problems with people
+getting libusb successfully built - between the Universal Build issues
+and the fact that we have to work hard to go find where it's installed
+and unravel the shared library thing -it's easier to just include it 
+here.
+
+This code is covered under GPL.
+
+This is meant to be a stop-gap until we can get rid of libusb and use
+the IoKit framework natively.
+
+08-11-08 robertlipe
diff --git a/mac/libusb/darwin.c b/mac/libusb/darwin.c
new file mode 100644 (file)
index 0000000..08b39a4
--- /dev/null
@@ -0,0 +1,1264 @@
+/*
+ * Darwin/MacOS X Support
+ *
+ * (c) 2002-2006 Nathan Hjelm <hjelmn@users.sourceforge.net>
+ *
+ * (06/26/2006):
+ *   - Bulk functions no longer use async transfer functions.
+ * (04/17/2005):
+ *   - Lots of minor fixes.
+ *   - Endpoint table now made by claim_interface to fix a bug.
+ *   - Merged Read/Write to make modifications easier.
+ * (03/25/2005):
+ *   - Fixed a bug when using asynchronous callbacks within a multi-threaded application.
+ * (03/14/2005):
+ *   - Added an endpoint table to speed up bulk transfers.
+ * 0.1.11 (02/22/2005):
+ *   - Updated error checking in read/write routines to check completion codes.
+ *   - Updated set_configuration so that the open interface is reclaimed before completion.
+ *   - Fixed several typos.
+ * 0.1.8 (01/12/2004):
+ *   - Fixed several memory leaks.
+ *   - Readded 10.0 support
+ *   - Added support for USB fuctions defined in 10.3 and above
+ * (01/02/2003):
+ *   - Applied a patch by Philip Edelbrock <phil@edgedesign.us> that fixes a bug in usb_control_msg.
+ * (12/16/2003):
+ *   - Even better error printing.
+ *   - Devices that cannot be opened can have their interfaces opened.
+ * 0.1.6 (05/12/2002):
+ *   - Fixed problem where libusb holds resources after program completion.
+ *   - Mouse should no longer freeze up now.
+ * 0.1.2 (02/13/2002):
+ *   - Bulk functions should work properly now.
+ * 0.1.1 (02/11/2002):
+ *   - Fixed major bug (device and interface need to be released after use)
+ * 0.1.0 (01/06/2002):
+ *   - Tested driver with gphoto (works great as long as Image Capture isn't running)
+ * 0.1d  (01/04/2002):
+ *   - Implimented clear_halt and resetep
+ *   - Uploaded to CVS.
+ * 0.1b  (01/04/2002):
+ *   - Added usb_debug line to bulk read and write function.
+ * 0.1a  (01/03/2002):
+ *   - Driver mostly completed using the macosx driver I wrote for my rioutil software.
+ *
+ * Derived from Linux version by Richard Tobin.
+ * Also partly derived from BSD version.
+ *
+ * This library is covered by the LGPL, read LICENSE for details.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+/* standard includes for darwin/os10 (IOKit) */
+#include <mach/mach_port.h>
+#include <IOKit/IOCFBundle.h>
+#include <IOKit/usb/IOUSBLib.h>
+#include <IOKit/IOCFPlugIn.h>
+
+#include "usbi.h"
+
+/* some defines */
+/* IOUSBInterfaceInferface */
+#if defined (kIOUSBInterfaceInterfaceID220)
+
+// #warning "libusb being compiled for 10.4 or later"
+#define usb_interface_t IOUSBInterfaceInterface220
+#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID220
+#define InterfaceVersion 220
+
+#elif defined (kIOUSBInterfaceInterfaceID197)
+
+// #warning "libusb being compiled for 10.3 or later"
+#define usb_interface_t IOUSBInterfaceInterface197
+#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID197
+#define InterfaceVersion 197
+
+#elif defined (kIOUSBInterfaceInterfaceID190)
+
+// #warning "libusb being compiled for 10.2 or later"
+#define usb_interface_t IOUSBInterfaceInterface190
+#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID190
+#define InterfaceVersion 190
+
+#elif defined (kIOUSBInterfaceInterfaceID182)
+
+// #warning "libusb being compiled for 10.1 or later"
+#define usb_interface_t IOUSBInterfaceInterface182
+#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID182
+#define InterfaceVersion 182
+
+#else
+
+/* No timeout functions available! Time to upgrade your os. */
+#warning "libusb being compiled without support for timeout bulk functions! 10.0 and up"
+#define usb_interface_t IOUSBInterfaceInterface
+#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID
+#define LIBUSB_NO_TIMEOUT_INTERFACE
+#define InterfaceVersion 180
+
+#endif
+
+/* IOUSBDeviceInterface */
+#if defined (kIOUSBDeviceInterfaceID197)
+
+#define usb_device_t    IOUSBDeviceInterface197
+#define DeviceInterfaceID kIOUSBDeviceInterfaceID197
+#define DeviceVersion 197
+
+#elif defined (kIOUSBDeviceInterfaceID187)
+
+#define usb_device_t    IOUSBDeviceInterface187
+#define DeviceInterfaceID kIOUSBDeviceInterfaceID187
+#define DeviceVersion 187
+
+#elif defined (kIOUSBDeviceInterfaceID182)
+
+#define usb_device_t    IOUSBDeviceInterface182
+#define DeviceInterfaceID kIOUSBDeviceInterfaceID182
+#define DeviceVersion 182
+
+#else
+
+#define usb_device_t    IOUSBDeviceInterface
+#define DeviceInterfaceID kIOUSBDeviceInterfaceID
+#define LIBUSB_NO_TIMEOUT_DEVICE
+#define LIBUSB_NO_SEIZE_DEVICE
+#define DeviceVersion 180
+
+#endif
+
+typedef IOReturn io_return_t;
+typedef IOCFPlugInInterface *io_cf_plugin_ref_t;
+typedef SInt32 s_int32_t;
+typedef IOReturn (*rw_async_func_t)(void *self, UInt8 pipeRef, void *buf, UInt32 size,
+                                   IOAsyncCallback1 callback, void *refcon);
+typedef IOReturn (*rw_async_to_func_t)(void *self, UInt8 pipeRef, void *buf, UInt32 size,
+                                      UInt32 noDataTimeout, UInt32 completionTimeout,
+                                      IOAsyncCallback1 callback, void *refcon);
+
+#if !defined(IO_OBJECT_NULL)
+#define IO_OBJECT_NULL ((io_object_t)0)
+#endif
+
+struct darwin_dev_handle {
+  usb_device_t **device;
+  usb_interface_t **interface;
+  int open;
+
+  /* stored translation table for pipes to endpoints */
+  int num_endpoints;
+  unsigned char *endpoint_addrs;
+};
+
+static IONotificationPortRef gNotifyPort;
+static mach_port_t masterPort = MACH_PORT_NULL;
+
+static void darwin_cleanup (void)
+{
+  IONotificationPortDestroy(gNotifyPort);
+  mach_port_deallocate(mach_task_self(), masterPort);
+}
+
+static char *darwin_error_str (int result) {
+  switch (result) {
+  case kIOReturnSuccess:
+    return "no error";
+  case kIOReturnNotOpen:
+    return "device not opened for exclusive access";
+  case kIOReturnNoDevice:
+    return "no connection to an IOService";
+  case kIOUSBNoAsyncPortErr:
+    return "no async port has been opened for interface";
+  case kIOReturnExclusiveAccess:
+    return "another process has device opened for exclusive access";
+  case kIOUSBPipeStalled:
+    return "pipe is stalled";
+  case kIOReturnError:
+    return "could not establish a connection to the Darwin kernel";
+  case kIOUSBTransactionTimeout:
+    return "transaction timed out";
+  case kIOReturnBadArgument:
+    return "invalid argument";
+  case kIOReturnAborted:
+    return "transaction aborted";
+  default:
+    return "unknown error";
+  }
+}
+
+/* not a valid errorno outside darwin.c */
+#define LUSBDARWINSTALL (ELAST+1)
+
+static int darwin_to_errno (int result) {
+  switch (result) {
+  case kIOReturnSuccess:
+    return 0;
+  case kIOReturnNotOpen:
+    return EBADF;
+  case kIOReturnNoDevice:
+  case kIOUSBNoAsyncPortErr:
+    return ENXIO;
+  case kIOReturnExclusiveAccess:
+    return EBUSY;
+  case kIOUSBPipeStalled:
+    return LUSBDARWINSTALL;
+  case kIOReturnBadArgument:
+    return EINVAL;
+  case kIOUSBTransactionTimeout:
+    return ETIMEDOUT;
+  case kIOReturnError:
+  default:
+    return 1;
+  }
+}
+
+static int usb_setup_iterator (io_iterator_t *deviceIterator)
+{
+  int result;
+  CFMutableDictionaryRef matchingDict;
+
+  /* set up the matching dictionary for class IOUSBDevice and its subclasses.
+     It will be consumed by the IOServiceGetMatchingServices call */
+  if ((matchingDict = IOServiceMatching(kIOUSBDeviceClassName)) == NULL) {
+    darwin_cleanup ();
+    
+    USB_ERROR_STR(-1, "libusb/darwin.c usb_setup_iterator: Could not create a matching dictionary.\n");
+  }
+
+  result = IOServiceGetMatchingServices(masterPort, matchingDict, deviceIterator);
+  matchingDict = NULL;
+
+  if (result != kIOReturnSuccess)
+    USB_ERROR_STR (-darwin_to_errno (result), "libusb/darwin.c usb_setup_iterator: IOServiceGetMatchingServices: %s\n",
+                  darwin_error_str(result));
+
+  return 0;
+}
+
+static usb_device_t **usb_get_next_device (io_iterator_t deviceIterator, UInt32 *locationp)
+{
+  io_cf_plugin_ref_t *plugInInterface = NULL;
+  usb_device_t **device;
+  io_service_t usbDevice;
+  long result, score;
+
+  if (!IOIteratorIsValid (deviceIterator) || !(usbDevice = IOIteratorNext(deviceIterator)))
+    return NULL;
+  
+  result = IOCreatePlugInInterfaceForService(usbDevice, kIOUSBDeviceUserClientTypeID,
+                                            kIOCFPlugInInterfaceID, &plugInInterface,
+                                            &score);
+  
+  result = IOObjectRelease(usbDevice);
+  if (result || !plugInInterface)
+    return NULL;
+  
+  (*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(DeviceInterfaceID),
+                                    (LPVOID)&device);
+  
+  (*plugInInterface)->Stop(plugInInterface);
+  IODestroyPlugInInterface (plugInInterface);
+  plugInInterface = NULL;
+  
+  (*(device))->GetLocationID(device, locationp);
+
+  return device;
+}
+
+int usb_os_open(usb_dev_handle *dev)
+{
+  struct darwin_dev_handle *device;
+
+  io_return_t result;
+  io_iterator_t deviceIterator;
+
+  usb_device_t **darwin_device;
+
+  UInt32 location = *((UInt32 *)dev->device->dev);
+  UInt32 dlocation;
+
+  if (!dev)
+    USB_ERROR(-ENXIO);
+
+  if (masterPort == MACH_PORT_NULL)
+    USB_ERROR(-EINVAL);
+
+  device = calloc(1, sizeof(struct darwin_dev_handle));
+  if (!device)
+    USB_ERROR(-ENOMEM);
+
+  if (usb_debug > 3)
+    fprintf(stderr, "usb_os_open: %04x:%04x\n",
+           dev->device->descriptor.idVendor,
+           dev->device->descriptor.idProduct);
+
+  if ((result = usb_setup_iterator (&deviceIterator)) < 0)
+    return result;
+
+  /* This port of libusb uses locations to keep track of devices. */
+  while ((darwin_device = usb_get_next_device (deviceIterator, &dlocation)) != NULL) {
+    if (dlocation == location)
+      break;
+
+    (*darwin_device)->Release(darwin_device);
+  }
+
+  IOObjectRelease(deviceIterator);
+  device->device = darwin_device;
+
+  if (device->device == NULL)
+    USB_ERROR_STR (-ENOENT, "usb_os_open: %s\n", "Device not found!");
+
+#if !defined (LIBUSB_NO_SEIZE_DEVICE)
+  result = (*(device->device))->USBDeviceOpenSeize (device->device);
+#else
+  /* No Seize in OS X 10.0 (Darwin 1.4) */
+  result = (*(device->device))->USBDeviceOpen (device->device);
+#endif
+
+  if (result != kIOReturnSuccess) {
+    switch (result) {
+    case kIOReturnExclusiveAccess:
+      if (usb_debug > 0)
+       fprintf (stderr, "usb_os_open(USBDeviceOpenSeize): %s\n", darwin_error_str(result));
+      break;
+    default:
+      (*(device->device))->Release (device->device);
+      USB_ERROR_STR(-darwin_to_errno (result), "usb_os_open(USBDeviceOpenSeize): %s",
+                   darwin_error_str(result));
+    }
+    
+    device->open = 0;
+  } else
+    device->open = 1;
+    
+  dev->impl_info = device;
+  dev->interface = -1;
+  dev->altsetting = -1;
+
+  device->num_endpoints  = 0;
+  device->endpoint_addrs = NULL;
+
+  return 0;
+}
+
+int usb_os_close(usb_dev_handle *dev)
+{
+  struct darwin_dev_handle *device;
+  io_return_t result;
+
+  if (!dev)
+    USB_ERROR(-ENXIO);
+
+  if ((device = dev->impl_info) == NULL)
+    USB_ERROR(-ENOENT);
+
+  usb_release_interface(dev, dev->interface);
+
+  if (usb_debug > 3)
+    fprintf(stderr, "usb_os_close: %04x:%04x\n",
+           dev->device->descriptor.idVendor,
+           dev->device->descriptor.idProduct);
+
+  if (device->open == 1)
+    result = (*(device->device))->USBDeviceClose(device->device);
+  else
+    result = kIOReturnSuccess;
+
+  /* device may not need to be released, but if it has to... */
+  (*(device->device))->Release(device->device);
+
+  if (result != kIOReturnSuccess)
+    USB_ERROR_STR(-darwin_to_errno(result), "usb_os_close(USBDeviceClose): %s", darwin_error_str(result));
+
+  free (device);
+
+  return 0;
+}
+
+static int get_endpoints (struct darwin_dev_handle *device)
+{
+  io_return_t ret;
+
+  u_int8_t numep, direction, number;
+  u_int8_t dont_care1, dont_care3;
+  u_int16_t dont_care2;
+
+  int i;
+
+  if (device == NULL || device->interface == NULL)
+    return -EINVAL;
+
+  if (usb_debug > 1)
+    fprintf(stderr, "libusb/darwin.c get_endpoints: building table of endpoints.\n");
+
+  /* retrieve the total number of endpoints on this interface */
+  ret = (*(device->interface))->GetNumEndpoints(device->interface, &numep);
+  if ( ret ) {
+    if ( usb_debug > 1 )
+      fprintf ( stderr, "get_endpoints: interface is %p\n", device->interface );
+
+    USB_ERROR_STR ( -ret, "get_endpoints: can't get number of endpoints for interface" );
+  }
+
+  free (device->endpoint_addrs);
+  device->endpoint_addrs = calloc (sizeof (unsigned char), numep);
+
+  /* iterate through pipe references */
+  for (i = 1 ; i <= numep ; i++) {
+    ret = (*(device->interface))->GetPipeProperties(device->interface, i, &direction, &number,
+                                                   &dont_care1, &dont_care2, &dont_care3);
+
+    if (ret != kIOReturnSuccess) {
+      fprintf (stderr, "get_endpoints: an error occurred getting pipe information on pipe %d\n",
+              i );
+      USB_ERROR_STR(-darwin_to_errno(ret), "get_endpoints(GetPipeProperties): %s", darwin_error_str(ret));
+    }
+
+    if (usb_debug > 1)
+      fprintf (stderr, "get_endpoints: Pipe %i: DIR: %i number: %i\n", i, direction, number);
+
+    device->endpoint_addrs[i - 1] = ((direction << 7 & USB_ENDPOINT_DIR_MASK) |
+                                    (number & USB_ENDPOINT_ADDRESS_MASK));
+  }
+
+  device->num_endpoints = numep;
+
+  if (usb_debug > 1)
+    fprintf(stderr, "libusb/darwin.c get_endpoints: complete.\n");
+  
+  return 0;
+}
+
+static int claim_interface (usb_dev_handle *dev, int interface)
+{
+  io_iterator_t interface_iterator;
+  io_service_t  usbInterface = IO_OBJECT_NULL;
+  io_return_t result;
+  io_cf_plugin_ref_t *plugInInterface = NULL;
+
+  IOUSBFindInterfaceRequest request;
+
+  struct darwin_dev_handle *device;
+  long score;
+  int current_interface;
+
+  device = dev->impl_info;
+
+  request.bInterfaceClass = kIOUSBFindInterfaceDontCare;
+  request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
+  request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
+  request.bAlternateSetting = kIOUSBFindInterfaceDontCare;
+
+  result = (*(device->device))->CreateInterfaceIterator(device->device, &request, &interface_iterator);
+  if (result != kIOReturnSuccess)
+    USB_ERROR_STR (-darwin_to_errno(result), "claim_interface(CreateInterfaceIterator): %s",
+                  darwin_error_str(result));
+
+  for ( current_interface=0 ; current_interface <= interface ; current_interface++ ) {
+    usbInterface = IOIteratorNext(interface_iterator);
+    if ( usb_debug > 3 )
+      fprintf ( stderr, "Interface %d of device is 0x%08x\n",
+               current_interface, usbInterface );
+  }
+
+  current_interface--;
+
+  /* the interface iterator is no longer needed, release it */
+  IOObjectRelease(interface_iterator);
+
+  if (!usbInterface) {
+    u_int8_t nConfig;                       /* Index of configuration to use */
+    IOUSBConfigurationDescriptorPtr configDesc; /* to describe which configuration to select */
+    /* Only a composite class device with no vendor-specific driver will
+       be configured. Otherwise, we need to do it ourselves, or there
+       will be no interfaces for the device. */
+
+    if ( usb_debug > 3 )
+      fprintf ( stderr,"claim_interface: No interface found; selecting configuration\n" );
+
+    result = (*(device->device))->GetNumberOfConfigurations ( device->device, &nConfig );
+    if (result != kIOReturnSuccess)
+      USB_ERROR_STR(-darwin_to_errno(result), "claim_interface(GetNumberOfConfigurations): %s",
+                   darwin_error_str(result));
+    
+    if (nConfig < 1)
+      USB_ERROR_STR(-ENXIO ,"claim_interface(GetNumberOfConfigurations): no configurations");
+    else if ( nConfig > 1 && usb_debug > 0 )
+      fprintf ( stderr, "claim_interface: device has more than one"
+               " configuration, using the first (warning)\n" );
+
+    if ( usb_debug > 3 )
+      fprintf ( stderr, "claim_interface: device has %d configuration%s\n",
+               (int)nConfig, (nConfig>1?"s":"") );
+
+    /* Always use the first configuration */
+    result = (*(device->device))->GetConfigurationDescriptorPtr ( (device->device), 0, &configDesc );
+    if (result != kIOReturnSuccess) {
+      if (device->open == 1) {
+        (*(device->device))->USBDeviceClose ( (device->device) );
+        (*(device->device))->Release ( (device->device) );
+      }
+
+      USB_ERROR_STR(-darwin_to_errno(result), "claim_interface(GetConfigurationDescriptorPtr): %s",
+                   darwin_error_str(result));
+    } else if ( usb_debug > 3 )
+      fprintf ( stderr, "claim_interface: configuration value is %d\n",
+               configDesc->bConfigurationValue );
+
+    if (device->open == 1) {
+      result = (*(device->device))->SetConfiguration ( (device->device), configDesc->bConfigurationValue );
+
+      if (result != kIOReturnSuccess) {
+       (*(device->device))->USBDeviceClose ( (device->device) );
+       (*(device->device))->Release ( (device->device) );
+
+       USB_ERROR_STR(-darwin_to_errno(result), "claim_interface(SetConfiguration): %s",
+                     darwin_error_str(result));
+      }
+
+      dev->config = configDesc->bConfigurationValue;
+    }
+    
+    request.bInterfaceClass = kIOUSBFindInterfaceDontCare;
+    request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
+    request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
+    request.bAlternateSetting = kIOUSBFindInterfaceDontCare;
+
+    /* Now go back and get the chosen interface */
+    result = (*(device->device))->CreateInterfaceIterator(device->device, &request, &interface_iterator);
+    if (result != kIOReturnSuccess)
+      USB_ERROR_STR (-darwin_to_errno(result), "claim_interface(CreateInterfaceIterator): %s",
+                    darwin_error_str(result));
+
+    for (current_interface = 0 ; current_interface <= interface ; current_interface++) {
+      usbInterface = IOIteratorNext(interface_iterator);
+
+      if ( usb_debug > 3 )
+       fprintf ( stderr, "claim_interface: Interface %d of device is 0x%08x\n",
+                 current_interface, usbInterface );
+    }
+    current_interface--;
+
+    /* the interface iterator is no longer needed, release it */
+    IOObjectRelease(interface_iterator);
+
+    if (!usbInterface)
+      USB_ERROR_STR (-ENOENT, "claim_interface: interface iterator returned NULL");
+  }
+
+  result = IOCreatePlugInInterfaceForService(usbInterface,
+                                            kIOUSBInterfaceUserClientTypeID,
+                                            kIOCFPlugInInterfaceID,
+                                            &plugInInterface, &score);
+  /* No longer need the usbInterface object after getting the plug-in */
+  result = IOObjectRelease(usbInterface);
+  if (result || !plugInInterface)
+    USB_ERROR(-ENOENT);
+
+  /* Now create the device interface for the interface */
+  result = (*plugInInterface)->QueryInterface(plugInInterface,
+                                             CFUUIDGetUUIDBytes(InterfaceInterfaceID),
+                                             (LPVOID) &device->interface);
+
+  /* No longer need the intermediate plug-in */
+  (*plugInInterface)->Stop(plugInInterface);
+  IODestroyPlugInInterface (plugInInterface);
+
+  if (result != kIOReturnSuccess)
+    USB_ERROR_STR(-darwin_to_errno(result), "claim_interface(QueryInterface): %s",
+                 darwin_error_str(result));
+
+  if (!device->interface)
+    USB_ERROR(-EACCES);
+
+  if ( usb_debug > 3 )
+    fprintf ( stderr, "claim_interface: Interface %d of device from QueryInterface is %p\n",
+             current_interface, device->interface);
+
+  /* claim the interface */
+  result = (*(device->interface))->USBInterfaceOpen(device->interface);
+  if (result)
+    USB_ERROR_STR(-darwin_to_errno(result), "claim_interface(USBInterfaceOpen): %s",
+                 darwin_error_str(result));
+
+  result = get_endpoints (device);
+
+  if (result) {
+    /* this should not happen */
+    usb_release_interface (dev, interface);
+    USB_ERROR_STR ( result, "claim_interface: could not build endpoint table");
+  }
+
+  return 0;
+}
+
+int usb_set_configuration (usb_dev_handle *dev, int configuration)
+{
+  struct darwin_dev_handle *device;
+  io_return_t result;
+  int interface;
+
+  if ( usb_debug > 3 )
+    fprintf ( stderr, "usb_set_configuration: called for config %x\n", configuration );
+
+  if (!dev)
+    USB_ERROR_STR ( -ENXIO, "usb_set_configuration: called with null device\n" );
+
+  if ((device = dev->impl_info) == NULL)
+    USB_ERROR_STR ( -ENOENT, "usb_set_configuration: device not properly initialized" );
+
+  /* Setting configuration will invalidate the interface, so we need
+     to reclaim it. First, dispose of existing interface, if any. */
+  interface = dev->interface;
+
+  if ( device->interface )
+    usb_release_interface(dev, dev->interface);
+
+  result = (*(device->device))->SetConfiguration(device->device, configuration);
+
+  if (result)
+    USB_ERROR_STR(-darwin_to_errno(result), "usb_set_configuration(SetConfiguration): %s",
+                 darwin_error_str(result));
+
+  /* Reclaim interface */
+  if (interface != -1)
+    result = usb_claim_interface (dev, interface);
+
+  dev->config = configuration;
+
+  return result;
+}
+
+int usb_claim_interface(usb_dev_handle *dev, int interface)
+{
+  struct darwin_dev_handle *device = dev->impl_info;
+
+  io_return_t result;
+
+  if ( usb_debug > 3 )
+    fprintf ( stderr, "usb_claim_interface: called for interface %d\n", interface );
+
+  if (!device)
+    USB_ERROR_STR ( -ENOENT, "usb_claim_interface: device is NULL" );
+
+  if (!(device->device))
+    USB_ERROR_STR ( -EINVAL, "usb_claim_interface: device->device is NULL" );
+
+  /* If we have already claimed an interface, release it */
+  if ( device->interface )
+    usb_release_interface(dev, dev->interface);
+
+  result = claim_interface ( dev, interface );
+  if ( result )
+    USB_ERROR_STR ( result, "usb_claim_interface: couldn't claim interface" );
+
+  dev->interface = interface;
+
+  /* interface is claimed and async IO is set up: return 0 */
+  return 0;
+}
+
+int usb_release_interface(usb_dev_handle *dev, int interface)
+{
+  struct darwin_dev_handle *device;
+  io_return_t result;
+
+  if (!dev)
+    USB_ERROR(-ENXIO);
+
+  if ((device = dev->impl_info) == NULL)
+    USB_ERROR(-ENOENT);
+
+  /* interface is not open */
+  if (!device->interface)
+    return 0;
+
+  result = (*(device->interface))->USBInterfaceClose(device->interface);
+
+  if (result != kIOReturnSuccess)
+    USB_ERROR_STR(-darwin_to_errno(result), "usb_release_interface(USBInterfaceClose): %s",
+                 darwin_error_str(result));
+
+  result = (*(device->interface))->Release(device->interface);
+
+  if (result != kIOReturnSuccess)
+    USB_ERROR_STR(-darwin_to_errno(result), "usb_release_interface(Release): %s",
+                 darwin_error_str(result));
+
+  device->interface = NULL;
+
+  free (device->endpoint_addrs);
+
+  device->num_endpoints  = 0;
+  device->endpoint_addrs = NULL;
+
+  dev->interface = -1;
+  dev->altsetting = -1;
+
+  return 0;
+}
+
+int usb_set_altinterface(usb_dev_handle *dev, int alternate)
+{
+  struct darwin_dev_handle *device;
+  io_return_t result;
+
+  if (!dev)
+    USB_ERROR(-ENXIO);
+
+  if ((device = dev->impl_info) == NULL)
+    USB_ERROR(-ENOENT);
+
+  /* interface is not open */
+  if (!device->interface)
+    USB_ERROR_STR(-EACCES, "usb_set_altinterface: interface used without being claimed");
+
+  result = (*(device->interface))->SetAlternateInterface(device->interface, alternate);
+
+  if (result)
+    USB_ERROR_STR(result, "usb_set_altinterface: could not set alternate interface");
+
+  dev->altsetting = alternate;
+
+  result = get_endpoints (device);
+  if (result) {
+    /* this should not happen */
+    USB_ERROR_STR ( result, "usb_set_altinterface: could not build endpoint table");
+  }
+
+  return 0;
+}
+
+/* simple function that figures out what pipeRef is associated with an endpoint */
+static int ep_to_pipeRef (struct darwin_dev_handle *device, int ep)
+{
+  int i;
+
+  if (usb_debug > 1)
+    fprintf(stderr, "libusb/darwin.c ep_to_pipeRef: Converting ep address to pipeRef.\n");
+
+  for (i = 0 ; i < device->num_endpoints ; i++)
+    if (device->endpoint_addrs[i] == ep)
+      return i + 1;
+
+  /* No pipe found with the correct endpoint address */
+  if (usb_debug > 1)
+    fprintf(stderr, "libusb/darwin.c ep_to_pipeRef: No pipeRef found with endpoint address 0x%02x.\n", ep);
+  
+  return -1;
+}
+
+static int usb_bulk_transfer (usb_dev_handle *dev, int ep, char *bytes, u_int32_t size, int timeout, int usb_bt_read)
+{
+  struct darwin_dev_handle *device;
+
+  io_return_t result = -1;
+
+  int pipeRef;
+
+  u_int8_t  transferType, direction, number, interval;
+  u_int16_t maxPacketSize;
+
+  if (!dev)
+    USB_ERROR_STR ( -ENXIO, "libusb/darwin.c usb_bulk_transfer: Called with NULL device" );
+
+  if ((device = dev->impl_info) == NULL)
+    USB_ERROR_STR ( -ENOENT, "libusb/darwin.c usb_bulk_transfer: Device not open" );
+
+  /* interface is not open */
+  if (!device->interface)
+    USB_ERROR_STR(-EACCES, "libusb/darwin.c usb_bulk_transfer: Interface used before it was opened");
+
+
+  /* Set up transfer */
+  if ((pipeRef = ep_to_pipeRef(device, ep)) < 0)
+    USB_ERROR_STR ( -EINVAL, "libusb/darwin.c usb_bulk_transfer: Invalid pipe reference" );
+
+  (*(device->interface))->GetPipeProperties (device->interface, pipeRef, &direction, &number,
+                                            &transferType, &maxPacketSize, &interval);
+  /* Transfer set up complete */
+
+  if (usb_debug > 0)
+    fprintf (stderr, "libusb/darwin.c usb_bulk_transfer: Transfering %i bytes of data on endpoint 0x%02x\n", size, ep);
+
+  /* Do bulk transfer */
+  if (transferType == kUSBInterrupt && usb_debug > 3)
+    fprintf (stderr, "libusb/darwin.c usb_bulk_transfer: USB pipe is an interrupt pipe. Timeouts will not be used.\n");
+
+#if !defined(LIBUSB_NO_TIMEOUT_INTERFACE)
+  if ( transferType != kUSBInterrupt) {
+    if (usb_bt_read != 0)
+      result = (*(device->interface))->ReadPipeTO (device->interface, pipeRef, bytes, (UInt32 *)&size, timeout, timeout);
+    else
+      result = (*(device->interface))->WritePipeTO (device->interface, pipeRef, bytes, size, timeout, timeout);
+
+    /* pipe bits may need to be cleared after a timeout. should this be done here or in user code? */
+    if (result == kIOUSBTransactionTimeout && (*(device->interface))->GetPipeStatus (device->interface, pipeRef) == kIOUSBPipeStalled)
+      usb_clear_halt (dev, ep);
+  } else
+#endif
+  {
+    if (usb_bt_read != 0)
+      result = (*(device->interface))->ReadPipe (device->interface, pipeRef, bytes, (UInt32 *)&size);
+    else
+      result = (*(device->interface))->WritePipe (device->interface, pipeRef, bytes, size);
+  }
+
+  if (result != kIOReturnSuccess)
+    USB_ERROR_STR (-darwin_to_errno (result), "libusb/darwin.c usb_bulk_transfer: %s", darwin_error_str (result));
+
+  return size;
+}
+
+#if 0
+/* NOT USED */
+/* argument to handle multiple parameters to rw_completed */
+struct rw_complete_arg {
+  UInt32        io_size;
+  IOReturn      result;
+  CFRunLoopRef  cf_loop;
+};
+
+static void rw_completed(void *refcon, io_return_t result, void *io_size)
+{
+  struct rw_complete_arg *rw_arg = (struct rw_complete_arg *)refcon;
+
+  if (usb_debug > 2)
+    fprintf(stderr, "io async operation completed: %s, size=%lu, result=0x%08x\n", darwin_error_str(result),
+           (UInt32)io_size, result);
+
+  rw_arg->io_size = (UInt32)io_size;
+  rw_arg->result  = result;
+
+  CFRunLoopStop(rw_arg->cf_loop);
+}
+
+static int usb_bulk_transfer_async (usb_dev_handle *dev, int ep, char *bytes, int size, int timeout,
+                             rw_async_func_t rw_async, rw_async_to_func_t rw_async_to)
+{
+  struct darwin_dev_handle *device;
+
+  io_return_t result = -1;
+
+  CFRunLoopSourceRef cfSource;
+  int pipeRef;
+
+  struct rw_complete_arg rw_arg;
+
+  u_int8_t  transferType;
+
+  /* None of the values below are used in libusb for bulk transfers */
+  u_int8_t  direction, number, interval;
+  u_int16_t maxPacketSize;
+
+  if (!dev)
+    USB_ERROR_STR ( -ENXIO, "usb_bulk_transfer: Called with NULL device" );
+
+  if ((device = dev->impl_info) == NULL)
+    USB_ERROR_STR ( -ENOENT, "usb_bulk_transfer: Device not open" );
+
+  /* interface is not open */
+  if (!device->interface)
+    USB_ERROR_STR(-EACCES, "usb_bulk_transfer: Interface used before it was opened");
+
+
+  /* Set up transfer */
+  if ((pipeRef = ep_to_pipeRef(device, ep)) < 0)
+    USB_ERROR_STR ( -EINVAL, "usb_bulk_transfer: Invalid pipe reference" );
+
+  (*(device->interface))->GetPipeProperties (device->interface, pipeRef, &direction, &number,
+                                            &transferType, &maxPacketSize, &interval);
+
+  bzero((void *)&rw_arg, sizeof(struct rw_complete_arg));
+  rw_arg.cf_loop = CFRunLoopGetCurrent();
+  CFRetain (rw_arg.cf_loop);
+
+  (*(device->interface))->CreateInterfaceAsyncEventSource(device->interface, &cfSource);
+  CFRunLoopAddSource(rw_arg.cf_loop, cfSource, kCFRunLoopDefaultMode);
+  /* Transfer set up complete */
+
+  if (usb_debug > 0)
+    fprintf (stderr, "libusb/darwin.c usb_bulk_transfer: Transfering %i bytes of data on endpoint 0x%02x\n",
+            size, ep);
+
+  /* Bulk transfer */
+  if (transferType == kUSBInterrupt && usb_debug > 3)
+    fprintf (stderr, "libusb/darwin.c usb_bulk_transfer: USB pipe is an interrupt pipe. Timeouts will not be used.\n");
+
+  if ( transferType != kUSBInterrupt && rw_async_to != NULL)
+
+    result = rw_async_to (device->interface, pipeRef, bytes, size, timeout, timeout,
+                         (IOAsyncCallback1)rw_completed, (void *)&rw_arg);
+  else
+    result = rw_async (device->interface, pipeRef, bytes, size, (IOAsyncCallback1)rw_completed,
+                      (void *)&rw_arg);
+
+  if (result == kIOReturnSuccess) {
+    /* wait for write to complete */
+    if (CFRunLoopRunInMode(kCFRunLoopDefaultMode, (timeout+999)/1000, true) == kCFRunLoopRunTimedOut) {
+      (*(device->interface))->AbortPipe(device->interface, pipeRef);
+      CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true); /* Pick up aborted callback */
+      if (usb_debug)
+       fprintf(stderr, "usb_bulk_transfer: timed out\n");
+    }
+  }
+
+  CFRunLoopRemoveSource(rw_arg.cf_loop, cfSource, kCFRunLoopDefaultMode);
+  CFRelease (rw_arg.cf_loop);
+  
+  /* Check the return code of both the write and completion functions. */
+  if (result != kIOReturnSuccess || (rw_arg.result != kIOReturnSuccess && 
+      rw_arg.result != kIOReturnAborted) ) {
+    int error_code;
+    char *error_str;
+
+    if (result == kIOReturnSuccess) {
+      error_code = darwin_to_errno (rw_arg.result);
+      error_str  = darwin_error_str (rw_arg.result);
+    } else {
+      error_code = darwin_to_errno(result);
+      error_str  = darwin_error_str (result);
+    }
+    
+    if (transferType != kUSBInterrupt && rw_async_to != NULL)
+      USB_ERROR_STR(-error_code, "usb_bulk_transfer (w/ Timeout): %s", error_str);
+    else
+      USB_ERROR_STR(-error_code, "usb_bulk_transfer (No Timeout): %s", error_str);
+  }
+
+  return rw_arg.io_size;
+}
+#endif
+
+int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout)
+{
+  int result;
+  
+  if (dev == NULL || dev->impl_info == NULL)
+    return -EINVAL;
+
+  if ((result = usb_bulk_transfer (dev, ep, bytes, size, timeout, 0)) < 0)
+    USB_ERROR_STR (result, "usb_bulk_write: An error occured during write (see messages above)");
+  
+  return result;
+}
+
+int usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout)
+{
+  int result;
+  
+  if (dev == NULL || dev->impl_info == NULL)
+    return -EINVAL;
+
+  ep |= 0x80;
+
+  if ((result = usb_bulk_transfer (dev, ep, bytes, size, timeout, 1)) < 0)
+    USB_ERROR_STR (result, "usb_bulk_read: An error occured during read (see messages above)");
+  
+  return result;
+}
+
+/* interrupt endpoints appear to be treated the same as non-interrupt endpoints under OSX/Darwin */
+int usb_interrupt_write(usb_dev_handle *dev, int ep, char *bytes, int size,
+       int timeout)
+{
+  return usb_bulk_write (dev, ep, bytes, size, timeout);
+}
+
+int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size,
+       int timeout)
+{
+  return usb_bulk_read (dev, ep, bytes, size, timeout);
+}
+
+int usb_control_msg(usb_dev_handle *dev, int requesttype, int request,
+                   int value, int index, char *bytes, int size, int timeout)
+{
+  struct darwin_dev_handle *device = dev->impl_info;
+
+  io_return_t result;
+
+#if !defined (LIBUSB_NO_TIMEOUT_DEVICE)
+  IOUSBDevRequestTO urequest;
+#else
+  IOUSBDevRequest urequest;
+#endif
+
+  if (usb_debug >= 3)
+    fprintf(stderr, "usb_control_msg: %d %d %d %d %p %d %d\n",
+            requesttype, request, value, index, bytes, size, timeout);
+
+  bzero(&urequest, sizeof(urequest));
+
+  urequest.bmRequestType = requesttype;
+  urequest.bRequest = request;
+  urequest.wValue = value;
+  urequest.wIndex = index;
+  urequest.wLength = size;
+  urequest.pData = bytes;
+#if !defined (LIBUSB_NO_TIMEOUT_DEVICE)
+  urequest.completionTimeout = timeout;
+  urequest.noDataTimeout = timeout;
+
+  result = (*(device->device))->DeviceRequestTO(device->device, &urequest);
+#else
+  result = (*(device->device))->DeviceRequest(device->device, &urequest);
+#endif
+  if (result != kIOReturnSuccess)
+    USB_ERROR_STR(-darwin_to_errno(result), "usb_control_msg(DeviceRequestTO): %s", darwin_error_str(result));
+
+  /* Bytes transfered is stored in the wLenDone field*/
+  return urequest.wLenDone;
+}
+
+int usb_os_find_busses(struct usb_bus **busses)
+{
+  struct usb_bus *fbus = NULL;
+
+  io_iterator_t deviceIterator;
+  io_return_t result;
+
+  usb_device_t **device;
+
+  UInt32 location;
+
+  char buf[20];
+  int i = 1;
+
+  /* Create a master port for communication with IOKit (this should
+     have been created if the user called usb_init() )*/
+  if (masterPort == MACH_PORT_NULL) {
+    usb_init ();
+
+    if (masterPort == MACH_PORT_NULL)
+      USB_ERROR(-ENOENT);
+  }
+
+  if ((result = usb_setup_iterator (&deviceIterator)) < 0)
+    return result;
+
+  while ((device = usb_get_next_device (deviceIterator, &location)) != NULL) {
+    struct usb_bus *bus;
+
+    if (location & 0x00ffffff)
+      continue;
+
+    bus = calloc(1, sizeof(struct usb_bus));
+    if (bus == NULL)
+      USB_ERROR(-ENOMEM);
+    
+    sprintf(buf, "%03i", i++);
+    bus->location = location;
+
+    strncpy(bus->dirname, buf, sizeof(bus->dirname) - 1);
+    bus->dirname[sizeof(bus->dirname) - 1] = 0;
+    
+    LIST_ADD(fbus, bus);
+    
+    if (usb_debug >= 2)
+      fprintf(stderr, "usb_os_find_busses: Found %s\n", bus->dirname);
+
+    (*(device))->Release(device);
+  }
+
+  IOObjectRelease(deviceIterator);
+
+  *busses = fbus;
+
+  return 0;
+}
+
+int usb_os_find_devices(struct usb_bus *bus, struct usb_device **devices)
+{
+  struct usb_device *fdev = NULL;
+
+  io_iterator_t deviceIterator;
+  io_return_t result;
+
+  usb_device_t **device;
+
+  u_int16_t address;
+  UInt32 location;
+  UInt32 bus_loc = bus->location;
+
+  /* for use in retrieving device description */
+  IOUSBDevRequest req;
+
+  /* a master port should have been created by usb_os_init */
+  if (masterPort == MACH_PORT_NULL)
+    USB_ERROR(-ENOENT);
+
+  if ((result = usb_setup_iterator (&deviceIterator)) < 0)
+    return result;
+
+  /* Set up request for device descriptor */
+  req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
+  req.bRequest = kUSBRqGetDescriptor;
+  req.wValue = kUSBDeviceDesc << 8;
+  req.wIndex = 0;
+  req.wLength = sizeof(IOUSBDeviceDescriptor);
+
+
+  while ((device = usb_get_next_device (deviceIterator, &location)) != NULL) {
+    unsigned char device_desc[DEVICE_DESC_LENGTH];
+
+    result = (*(device))->GetDeviceAddress(device, (USBDeviceAddress *)&address);
+
+    if (usb_debug >= 2)
+      fprintf(stderr, "usb_os_find_devices: Found USB device at location 0x%08lx\n", location);
+
+    /* first byte of location appears to be associated with the device's bus */
+    if (location >> 24 == bus_loc >> 24) {
+      struct usb_device *dev;
+
+      dev = calloc(1, sizeof(struct usb_device));
+      if (dev == NULL)
+       USB_ERROR(-ENOMEM);
+
+      dev->bus = bus;
+
+      req.pData = device_desc;
+      result = (*(device))->DeviceRequest(device, &req);
+
+      usb_parse_descriptor(device_desc, "bbwbbbbwwwbbbb", &dev->descriptor);
+
+      sprintf(dev->filename, "%03i-%04x-%04x-%02x-%02x", address,
+             dev->descriptor.idVendor, dev->descriptor.idProduct,
+             dev->descriptor.bDeviceClass, dev->descriptor.bDeviceSubClass);
+
+      dev->dev = (USBDeviceAddress *)malloc(4);
+      memcpy(dev->dev, &location, 4);
+
+      LIST_ADD(fdev, dev);
+
+      if (usb_debug >= 2)
+       fprintf(stderr, "usb_os_find_devices: Found %s on %s at location 0x%08lx\n",
+               dev->filename, bus->dirname, location);
+    }
+
+    /* release the device now */
+    (*(device))->Release(device);
+  }
+
+  IOObjectRelease(deviceIterator);
+
+  *devices = fdev;
+
+  return 0;
+}
+
+int usb_os_determine_children(struct usb_bus *bus)
+{
+  /* Nothing yet */
+  return 0;
+}
+
+void usb_os_init(void)
+{
+  if (masterPort == MACH_PORT_NULL) {
+    IOMasterPort(masterPort, &masterPort);
+    
+    gNotifyPort = IONotificationPortCreate(masterPort);
+  }
+}
+
+void usb_os_cleanup (void)
+{
+  if (masterPort != MACH_PORT_NULL)
+    darwin_cleanup ();
+}
+
+int usb_resetep(usb_dev_handle *dev, unsigned int ep)
+{
+  struct darwin_dev_handle *device;
+
+  io_return_t result = -1;
+
+  int pipeRef;
+
+  if (!dev)
+    USB_ERROR(-ENXIO);
+
+  if ((device = dev->impl_info) == NULL)
+    USB_ERROR(-ENOENT);
+
+  /* interface is not open */
+  if (!device->interface)
+    USB_ERROR_STR(-EACCES, "usb_resetep: interface used without being claimed");
+
+  if ((pipeRef = ep_to_pipeRef(device, ep)) == -1)
+    USB_ERROR(-EINVAL);
+
+  result = (*(device->interface))->ResetPipe(device->interface, pipeRef);
+
+  if (result != kIOReturnSuccess)
+    USB_ERROR_STR(-darwin_to_errno(result), "usb_resetep(ResetPipe): %s", darwin_error_str(result));
+
+  return 0;
+}
+
+int usb_clear_halt(usb_dev_handle *dev, unsigned int ep)
+{
+  struct darwin_dev_handle *device;
+
+  io_return_t result = -1;
+
+  int pipeRef;
+
+  if (!dev)
+    USB_ERROR(-ENXIO);
+
+  if ((device = dev->impl_info) == NULL)
+    USB_ERROR(-ENOENT);
+
+  /* interface is not open */
+  if (!device->interface)
+    USB_ERROR_STR(-EACCES, "usb_clear_halt: interface used without being claimed");
+
+  if ((pipeRef = ep_to_pipeRef(device, ep)) == -1)
+    USB_ERROR(-EINVAL);
+
+#if (InterfaceVersion < 190)
+  result = (*(device->interface))->ClearPipeStall(device->interface, pipeRef);
+#else
+  /* newer versions of darwin support clearing additional bits on the device's endpoint */
+  result = (*(device->interface))->ClearPipeStallBothEnds(device->interface, pipeRef);
+#endif
+
+  if (result != kIOReturnSuccess)
+    USB_ERROR_STR(-darwin_to_errno(result), "usb_clear_halt(ClearPipeStall): %s", darwin_error_str(result));
+
+  return 0;
+}
+
+int usb_reset(usb_dev_handle *dev)
+{
+  struct darwin_dev_handle *device;
+  
+  io_return_t result;
+
+  if (!dev)
+    USB_ERROR(-ENXIO);
+
+  if ((device = dev->impl_info) == NULL)
+    USB_ERROR(-ENOENT);
+
+  if (!device->device)
+    USB_ERROR_STR(-ENOENT, "usb_reset: no such device");
+
+  result = (*(device->device))->ResetDevice(device->device);
+
+  if (result != kIOReturnSuccess)
+    USB_ERROR_STR(-darwin_to_errno(result), "usb_reset(ResetDevice): %s", darwin_error_str(result));
+  
+  return 0;
+}
diff --git a/mac/libusb/descriptors.c b/mac/libusb/descriptors.c
new file mode 100644 (file)
index 0000000..0146a82
--- /dev/null
@@ -0,0 +1,520 @@
+/*
+ * Parses descriptors
+ *
+ * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com>
+ *
+ * This library is covered by the LGPL, read LICENSE for details.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include "usbi.h"
+
+int usb_get_descriptor_by_endpoint(usb_dev_handle *udev, int ep,
+       unsigned char type, unsigned char index, void *buf, int size)
+{
+  memset(buf, 0, size);
+
+  return usb_control_msg(udev, ep | USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
+                        (type << 8) + index, 0, buf, size, 1000);
+}
+
+int usb_get_descriptor(usb_dev_handle *udev, unsigned char type,
+       unsigned char index, void *buf, int size)
+{
+  memset(buf, 0, size);
+
+  return usb_control_msg(udev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
+                        (type << 8) + index, 0, buf, size, 1000);
+}
+
+int usb_parse_descriptor(unsigned char *source, char *description, void *dest)
+{
+  unsigned char *sp = source, *dp = dest;
+  uint16_t w;
+  uint32_t d;
+  char *cp;
+
+  for (cp = description; *cp; cp++) {
+    switch (*cp) {
+    case 'b':  /* 8-bit byte */
+      *dp++ = *sp++;
+      break;
+    case 'w':  /* 16-bit word, convert from little endian to CPU */
+      w = (sp[1] << 8) | sp[0]; sp += 2;
+      dp += ((unsigned long)dp & 1);   /* Align to word boundary */
+      *((uint16_t *)dp) = w; dp += 2;
+      break;
+    case 'd':  /* 32-bit dword, convert from little endian to CPU */
+      d = (sp[3] << 24) | (sp[2] << 16) | (sp[1] << 8) | sp[0]; sp += 4;
+      dp += ((unsigned long)dp & 2);   /* Align to dword boundary */
+      *((uint32_t *)dp) = d; dp += 4;
+      break;
+    /* These two characters are undocumented and just a hack for Linux */
+    case 'W':  /* 16-bit word, keep CPU endianess */
+      dp += ((unsigned long)dp & 1);   /* Align to word boundary */
+      memcpy(dp, sp, 2); sp += 2; dp += 2;
+      break;
+    case 'D':  /* 32-bit dword, keep CPU endianess */
+      dp += ((unsigned long)dp & 2);   /* Align to dword boundary */
+      memcpy(dp, sp, 4); sp += 4; dp += 4;
+      break;
+    }
+  }
+
+  return sp - source;
+}
+
+/*
+ * This code looks surprisingly similar to the code I wrote for the Linux
+ * kernel. It's not a coincidence :)
+ */
+
+static int usb_parse_endpoint(struct usb_endpoint_descriptor *endpoint, unsigned char *buffer, int size)
+{
+  struct usb_descriptor_header header;
+  unsigned char *begin;
+  int parsed = 0, len, numskipped;
+
+  usb_parse_descriptor(buffer, "bb", &header);
+
+  /* Everything should be fine being passed into here, but we sanity */
+  /*  check JIC */
+  if (header.bLength > size) {
+    if (usb_debug >= 1)
+      fprintf(stderr, "ran out of descriptors parsing\n");
+    return -1;
+  }
+                
+  if (header.bDescriptorType != USB_DT_ENDPOINT) {
+    if (usb_debug >= 2)
+      fprintf(stderr, "unexpected descriptor 0x%X, expecting endpoint descriptor, type 0x%X\n",
+         header.bDescriptorType, USB_DT_ENDPOINT);
+    return parsed;
+  }
+
+  if (header.bLength >= ENDPOINT_AUDIO_DESC_LENGTH)
+    usb_parse_descriptor(buffer, "bbbbwbbb", endpoint);
+  else if (header.bLength >= ENDPOINT_DESC_LENGTH)
+    usb_parse_descriptor(buffer, "bbbbwb", endpoint);
+
+  buffer += header.bLength;
+  size -= header.bLength;
+  parsed += header.bLength;
+
+  /* Skip over the rest of the Class Specific or Vendor Specific */
+  /*  descriptors */
+  begin = buffer;
+  numskipped = 0;
+  while (size >= DESC_HEADER_LENGTH) {
+    usb_parse_descriptor(buffer, "bb", &header);
+
+    if (header.bLength < 2) {
+      if (usb_debug >= 1)
+        fprintf(stderr, "invalid descriptor length of %d\n", header.bLength);
+      return -1;
+    }
+
+    /* If we find another "proper" descriptor then we're done  */
+    if ((header.bDescriptorType == USB_DT_ENDPOINT) ||
+        (header.bDescriptorType == USB_DT_INTERFACE) ||
+        (header.bDescriptorType == USB_DT_CONFIG) ||
+        (header.bDescriptorType == USB_DT_DEVICE))
+      break;
+
+    if (usb_debug >= 1)
+      fprintf(stderr, "skipping descriptor 0x%X\n", header.bDescriptorType);
+    numskipped++;
+
+    buffer += header.bLength;
+    size -= header.bLength;
+    parsed += header.bLength;
+  }
+
+  if (numskipped && usb_debug >= 2)
+    fprintf(stderr, "skipped %d class/vendor specific endpoint descriptors\n", numskipped);
+
+  /* Copy any unknown descriptors into a storage area for drivers */
+  /*  to later parse */
+  len = (int)(buffer - begin);
+  if (!len) {
+    endpoint->extra = NULL;
+    endpoint->extralen = 0;
+    return parsed;
+  }
+
+  endpoint->extra = malloc(len);
+  if (!endpoint->extra) {
+    if (usb_debug >= 1)
+      fprintf(stderr, "couldn't allocate memory for endpoint extra descriptors\n");
+    endpoint->extralen = 0;
+    return parsed;
+  }
+
+  memcpy(endpoint->extra, begin, len);
+  endpoint->extralen = len;
+
+  return parsed;
+}
+
+static int usb_parse_interface(struct usb_interface *interface,
+       unsigned char *buffer, int size)
+{
+  int i, len, numskipped, retval, parsed = 0;
+  struct usb_descriptor_header header;
+  struct usb_interface_descriptor *ifp;
+  unsigned char *begin;
+
+  interface->num_altsetting = 0;
+
+  while (size >= INTERFACE_DESC_LENGTH) {
+    interface->altsetting = realloc(interface->altsetting, sizeof(struct usb_interface_descriptor) * (interface->num_altsetting + 1));
+    if (!interface->altsetting) {
+      if (usb_debug >= 1)
+        fprintf(stderr, "couldn't malloc interface->altsetting\n");
+      return -1;
+    }
+
+    ifp = interface->altsetting + interface->num_altsetting;
+    interface->num_altsetting++;
+
+    usb_parse_descriptor(buffer, "bbbbbbbbb", ifp);
+
+    /* Skip over the interface */
+    buffer += ifp->bLength;
+    parsed += ifp->bLength;
+    size -= ifp->bLength;
+
+    begin = buffer;
+    numskipped = 0;
+
+    /* Skip over any interface, class or vendor descriptors */
+    while (size >= DESC_HEADER_LENGTH) {
+      usb_parse_descriptor(buffer, "bb", &header);
+
+      if (header.bLength < 2) {
+        if (usb_debug >= 1)
+          fprintf(stderr, "invalid descriptor length of %d\n", header.bLength);
+        return -1;
+      }
+
+      /* If we find another "proper" descriptor then we're done */
+      if ((header.bDescriptorType == USB_DT_INTERFACE) ||
+          (header.bDescriptorType == USB_DT_ENDPOINT) ||
+          (header.bDescriptorType == USB_DT_CONFIG) ||
+          (header.bDescriptorType == USB_DT_DEVICE))
+        break;
+
+      numskipped++;
+
+      buffer += header.bLength;
+      parsed += header.bLength;
+      size -= header.bLength;
+    }
+
+    if (numskipped && usb_debug >= 2)
+      fprintf(stderr, "skipped %d class/vendor specific interface descriptors\n", numskipped);
+
+    /* Copy any unknown descriptors into a storage area for */
+    /*  drivers to later parse */
+    len = (int)(buffer - begin);
+    if (!len) {
+      ifp->extra = NULL;
+      ifp->extralen = 0;
+    } else {
+      ifp->extra = malloc(len);
+      if (!ifp->extra) {
+        if (usb_debug >= 1)
+          fprintf(stderr, "couldn't allocate memory for interface extra descriptors\n");
+        ifp->extralen = 0;
+        return -1;
+      }
+      memcpy(ifp->extra, begin, len);
+      ifp->extralen = len;
+    }
+
+    /* Did we hit an unexpected descriptor? */
+    usb_parse_descriptor(buffer, "bb", &header);
+    if ((size >= DESC_HEADER_LENGTH) &&
+        ((header.bDescriptorType == USB_DT_CONFIG) ||
+        (header.bDescriptorType == USB_DT_DEVICE)))
+      return parsed;
+
+    if (ifp->bNumEndpoints > USB_MAXENDPOINTS) {
+      if (usb_debug >= 1)
+        fprintf(stderr, "too many endpoints\n");
+      return -1;
+    }
+
+    if (ifp->bNumEndpoints > 0) {
+      ifp->endpoint = (struct usb_endpoint_descriptor *)
+                       malloc(ifp->bNumEndpoints *
+                       sizeof(struct usb_endpoint_descriptor));
+      if (!ifp->endpoint) {
+        if (usb_debug >= 1)
+          fprintf(stderr, "couldn't allocate memory for ifp->endpoint\n");
+        return -1;      
+      }
+
+      memset(ifp->endpoint, 0, ifp->bNumEndpoints *
+             sizeof(struct usb_endpoint_descriptor));
+
+      for (i = 0; i < ifp->bNumEndpoints; i++) {
+        usb_parse_descriptor(buffer, "bb", &header);
+  
+        if (header.bLength > size) {
+          if (usb_debug >= 1)
+            fprintf(stderr, "ran out of descriptors parsing\n");
+          return -1;
+        }
+                
+        retval = usb_parse_endpoint(ifp->endpoint + i, buffer, size);
+        if (retval < 0)
+          return retval;
+
+        buffer += retval;
+        parsed += retval;
+        size -= retval;
+      }
+    } else
+      ifp->endpoint = NULL;
+
+    /* We check to see if it's an alternate to this one */
+    ifp = (struct usb_interface_descriptor *)buffer;
+    if (size < USB_DT_INTERFACE_SIZE ||
+        ifp->bDescriptorType != USB_DT_INTERFACE ||
+        !ifp->bAlternateSetting)
+      return parsed;
+  }
+
+  return parsed;
+}
+
+int usb_parse_configuration(struct usb_config_descriptor *config,
+       unsigned char *buffer)
+{
+  int i, retval, size;
+  struct usb_descriptor_header header;
+
+  usb_parse_descriptor(buffer, "bbwbbbbb", config);
+  size = config->wTotalLength;
+
+  if (config->bNumInterfaces > USB_MAXINTERFACES) {
+    if (usb_debug >= 1)
+      fprintf(stderr, "too many interfaces\n");
+    return -1;
+  }
+
+  config->interface = (struct usb_interface *)
+                       malloc(config->bNumInterfaces *
+                       sizeof(struct usb_interface));
+  if (!config->interface) {
+    if (usb_debug >= 1)
+      fprintf(stderr, "out of memory\n");
+    return -1;      
+  }
+
+  memset(config->interface, 0, config->bNumInterfaces * sizeof(struct usb_interface));
+
+  buffer += config->bLength;
+  size -= config->bLength;
+        
+  config->extra = NULL;
+  config->extralen = 0;
+
+  for (i = 0; i < config->bNumInterfaces; i++) {
+    int numskipped, len;
+    unsigned char *begin;
+
+    /* Skip over the rest of the Class Specific or Vendor */
+    /*  Specific descriptors */
+    begin = buffer;
+    numskipped = 0;
+    while (size >= DESC_HEADER_LENGTH) {
+      usb_parse_descriptor(buffer, "bb", &header);
+
+      if ((header.bLength > size) || (header.bLength < DESC_HEADER_LENGTH)) {
+        if (usb_debug >= 1)
+          fprintf(stderr, "invalid descriptor length of %d\n", header.bLength);
+        return -1;
+      }
+
+      /* If we find another "proper" descriptor then we're done */
+      if ((header.bDescriptorType == USB_DT_ENDPOINT) ||
+          (header.bDescriptorType == USB_DT_INTERFACE) ||
+          (header.bDescriptorType == USB_DT_CONFIG) ||
+          (header.bDescriptorType == USB_DT_DEVICE))
+        break;
+
+      if (usb_debug >= 2)
+        fprintf(stderr, "skipping descriptor 0x%X\n", header.bDescriptorType);
+      numskipped++;
+
+      buffer += header.bLength;
+      size -= header.bLength;
+    }
+
+    if (numskipped && usb_debug >= 2)
+      fprintf(stderr, "skipped %d class/vendor specific endpoint descriptors\n", numskipped);
+
+    /* Copy any unknown descriptors into a storage area for */
+    /*  drivers to later parse */
+    len = (int)(buffer - begin);
+    if (len) {
+      /* FIXME: We should realloc and append here */
+      if (!config->extralen) {
+        config->extra = malloc(len);
+        if (!config->extra) {
+          if (usb_debug >= 1)
+            fprintf(stderr, "couldn't allocate memory for config extra descriptors\n");
+          config->extralen = 0;
+          return -1;
+        }
+
+        memcpy(config->extra, begin, len);
+        config->extralen = len;
+      }
+    }
+
+    retval = usb_parse_interface(config->interface + i, buffer, size);
+    if (retval < 0)
+      return retval;
+
+    buffer += retval;
+    size -= retval;
+  }
+
+  return size;
+}
+
+void usb_destroy_configuration(struct usb_device *dev)
+{
+  int c, i, j, k;
+        
+  if (!dev->config)
+    return;
+
+  for (c = 0; c < dev->descriptor.bNumConfigurations; c++) {
+    struct usb_config_descriptor *cf = &dev->config[c];
+
+    if (!cf->interface)
+      continue;
+
+    for (i = 0; i < cf->bNumInterfaces; i++) {
+      struct usb_interface *ifp = &cf->interface[i];
+                                
+      if (!ifp->altsetting)
+        continue;
+
+      for (j = 0; j < ifp->num_altsetting; j++) {
+        struct usb_interface_descriptor *as = &ifp->altsetting[j];
+                                        
+        if (as->extra)
+          free(as->extra);
+
+        if (!as->endpoint)
+          continue;
+                                        
+        for (k = 0; k < as->bNumEndpoints; k++) {
+          if (as->endpoint[k].extra)
+            free(as->endpoint[k].extra);
+        }       
+        free(as->endpoint);
+      }
+
+      free(ifp->altsetting);
+    }
+
+    free(cf->interface);
+  }
+
+  free(dev->config);
+}
+
+void usb_fetch_and_parse_descriptors(usb_dev_handle *udev)
+{
+  struct usb_device *dev = udev->device;
+  int i;
+
+  if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG) {
+    if (usb_debug >= 1)
+      fprintf(stderr, "Too many configurations (%d > %d)\n", dev->descriptor.bNumConfigurations, USB_MAXCONFIG);
+    return;
+  }
+
+  if (dev->descriptor.bNumConfigurations < 1) {
+    if (usb_debug >= 1)
+      fprintf(stderr, "Not enough configurations (%d < %d)\n", dev->descriptor.bNumConfigurations, 1);
+    return;
+  }
+
+  dev->config = (struct usb_config_descriptor *)malloc(dev->descriptor.bNumConfigurations * sizeof(struct usb_config_descriptor));
+  if (!dev->config) {
+    if (usb_debug >= 1)
+      fprintf(stderr, "Unable to allocate memory for config descriptor\n");
+    return;
+  }
+
+  memset(dev->config, 0, dev->descriptor.bNumConfigurations *
+       sizeof(struct usb_config_descriptor));
+
+  for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
+    unsigned char buffer[8], *bigbuffer;
+    struct usb_config_descriptor config;
+    int res;
+
+    /* Get the first 8 bytes so we can figure out what the total length is */
+    res = usb_get_descriptor(udev, USB_DT_CONFIG, i, buffer, 8);
+    if (res < 8) {
+      if (usb_debug >= 1) {
+        if (res < 0)
+          fprintf(stderr, "Unable to get descriptor (%d)\n", res);
+        else
+          fprintf(stderr, "Config descriptor too short (expected %d, got %d)\n", 8, res);
+      }
+
+      goto err;
+    }
+
+    usb_parse_descriptor(buffer, "bbw", &config);
+
+    bigbuffer = malloc(config.wTotalLength);
+    if (!bigbuffer) {
+      if (usb_debug >= 1)
+        fprintf(stderr, "Unable to allocate memory for descriptors\n");
+      goto err;
+    }
+
+    res = usb_get_descriptor(udev, USB_DT_CONFIG, i, bigbuffer, config.wTotalLength);
+    if (res < config.wTotalLength) {
+      if (usb_debug >= 1) {
+        if (res < 0)
+          fprintf(stderr, "Unable to get descriptor (%d)\n", res);
+        else
+          fprintf(stderr, "Config descriptor too short (expected %d, got %d)\n", config.wTotalLength, res);
+      }
+
+      free(bigbuffer);
+      goto err;
+    }
+
+    res = usb_parse_configuration(&dev->config[i], bigbuffer);
+    if (usb_debug >= 2) {
+      if (res > 0)
+        fprintf(stderr, "Descriptor data still left\n");
+      else if (res < 0)
+        fprintf(stderr, "Unable to parse descriptors\n");
+    }
+
+    free(bigbuffer);
+  }
+
+  return;
+
+err:
+  free(dev->config);
+
+  dev->config = NULL;
+}
+
diff --git a/mac/libusb/error.c b/mac/libusb/error.c
new file mode 100644 (file)
index 0000000..f7d496d
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * USB Error messages
+ *
+ * Copyright (c) 2000-2001 Johannes Erdfelt <johannes@erdfelt.com>
+ *
+ * This library is covered by the LGPL, read LICENSE for details.
+ */
+
+#include <errno.h>
+#include <string.h>
+
+#include "usb.h"
+#include "error.h"
+
+char usb_error_str[1024] = "";
+int usb_error_errno = 0;
+usb_error_type_t usb_error_type = USB_ERROR_TYPE_NONE;
+
+char *usb_strerror(void)
+{
+  switch (usb_error_type) {
+  case USB_ERROR_TYPE_NONE:
+    return "No error";
+  case USB_ERROR_TYPE_STRING:
+    return usb_error_str;
+  case USB_ERROR_TYPE_ERRNO:
+    if (usb_error_errno > -USB_ERROR_BEGIN)
+      return strerror(usb_error_errno);
+    else
+      /* Any error we don't know falls under here */
+      return "Unknown error";
+  }
+
+  return "Unknown error";
+}
+
diff --git a/mac/libusb/error.h b/mac/libusb/error.h
new file mode 100644 (file)
index 0000000..173e6fd
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef _ERROR_H_
+#define _ERROR_H_
+
+typedef enum {
+  USB_ERROR_TYPE_NONE = 0,
+  USB_ERROR_TYPE_STRING,
+  USB_ERROR_TYPE_ERRNO,
+} usb_error_type_t;
+
+extern char usb_error_str[1024];
+extern int usb_error_errno;
+extern usb_error_type_t usb_error_type;
+
+#define USB_ERROR(x) \
+       do { \
+          usb_error_type = USB_ERROR_TYPE_ERRNO; \
+          usb_error_errno = x; \
+         return x; \
+       } while (0)
+
+#define USB_ERROR_STR(x, format, args...) \
+       do { \
+         usb_error_type = USB_ERROR_TYPE_STRING; \
+         snprintf(usb_error_str, sizeof(usb_error_str) - 1, format, ## args); \
+          if (usb_debug >= 2) \
+            fprintf(stderr, "USB error: %s\n", usb_error_str); \
+         return x; \
+       } while (0)
+
+#endif /* _ERROR_H_ */
+
diff --git a/mac/libusb/usb.c b/mac/libusb/usb.c
new file mode 100644 (file)
index 0000000..9b8773e
--- /dev/null
@@ -0,0 +1,307 @@
+/*
+ * Main API entry point
+ *
+ * Copyright (c) 2000-2003 Johannes Erdfelt <johannes@erdfelt.com>
+ *
+ * This library is covered by the LGPL, read LICENSE for details.
+ */
+
+#include <stdlib.h>    /* getenv */
+#include <stdio.h>     /* stderr */
+#include <string.h>    /* strcmp */
+#include <errno.h>
+
+#include "usbi.h"
+
+int usb_debug = 0;
+struct usb_bus *usb_busses = NULL;
+
+int usb_find_busses(void)
+{
+  struct usb_bus *busses, *bus;
+  int ret, changes = 0;
+
+  ret = usb_os_find_busses(&busses);
+  if (ret < 0)
+    return ret;
+
+  /*
+   * Now walk through all of the busses we know about and compare against
+   * this new list. Any duplicates will be removed from the new list.
+   * If we don't find it in the new list, the bus was removed. Any
+   * busses still in the new list, are new to us.
+   */
+  bus = usb_busses;
+  while (bus) {
+    int found = 0;
+    struct usb_bus *nbus, *tbus = bus->next;
+
+    nbus = busses;
+    while (nbus) {
+      struct usb_bus *tnbus = nbus->next;
+
+      if (!strcmp(bus->dirname, nbus->dirname)) {
+        /* Remove it from the new busses list */
+        LIST_DEL(busses, nbus);
+
+        usb_free_bus(nbus);
+        found = 1;
+        break;
+      }
+
+      nbus = tnbus;
+    }
+
+    if (!found) {
+      /* The bus was removed from the system */
+      LIST_DEL(usb_busses, bus);
+      usb_free_bus(bus);
+      changes++;
+    }
+
+    bus = tbus;
+  }
+
+  /*
+   * Anything on the *busses list is new. So add them to usb_busses and
+   * process them like the new bus it is.
+   */
+  bus = busses;
+  while (bus) {
+    struct usb_bus *tbus = bus->next;
+
+    /*
+     * Remove it from the temporary list first and add it to the real
+     * usb_busses list.
+     */
+    LIST_DEL(busses, bus);
+
+    LIST_ADD(usb_busses, bus);
+
+    changes++;
+
+    bus = tbus;
+  }
+
+  return changes;
+}
+
+int usb_find_devices(void)
+{
+  struct usb_bus *bus;
+  int ret, changes = 0;
+
+  for (bus = usb_busses; bus; bus = bus->next) {
+    struct usb_device *devices, *dev;
+
+    /* Find all of the devices and put them into a temporary list */
+    ret = usb_os_find_devices(bus, &devices);
+    if (ret < 0)
+      return ret;
+
+    /*
+     * Now walk through all of the devices we know about and compare
+     * against this new list. Any duplicates will be removed from the new
+     * list. If we don't find it in the new list, the device was removed.
+     * Any devices still in the new list, are new to us.
+     */
+    dev = bus->devices;
+    while (dev) {
+      int found = 0;
+      struct usb_device *ndev, *tdev = dev->next;
+
+      ndev = devices;
+      while (ndev) {
+        struct usb_device *tndev = ndev->next;
+
+        if (!strcmp(dev->filename, ndev->filename)) {
+          /* Remove it from the new devices list */
+          LIST_DEL(devices, ndev);
+
+          usb_free_dev(ndev);
+          found = 1;
+          break;
+        }
+
+        ndev = tndev;
+      }
+
+      if (!found) {
+        /* The device was removed from the system */
+        LIST_DEL(bus->devices, dev);
+        usb_free_dev(dev);
+        changes++;
+      }
+
+      dev = tdev;
+    }
+
+    /*
+     * Anything on the *devices list is new. So add them to bus->devices and
+     * process them like the new device it is.
+     */
+    dev = devices;
+    while (dev) {
+      struct usb_device *tdev = dev->next;
+
+      /*
+       * Remove it from the temporary list first and add it to the real
+       * bus->devices list.
+       */
+      LIST_DEL(devices, dev);
+
+      LIST_ADD(bus->devices, dev);
+
+      /*
+       * Some ports fetch the descriptors on scanning (like Linux) so we don't
+       * need to fetch them again.
+       */
+      if (!dev->config) {
+        usb_dev_handle *udev;
+
+        udev = usb_open(dev);
+        if (udev) {
+          usb_fetch_and_parse_descriptors(udev);
+
+          usb_close(udev);
+        }
+      }
+
+      changes++;
+
+      dev = tdev;
+    }
+
+    usb_os_determine_children(bus);
+  }
+
+  return changes;
+}
+
+void usb_set_debug(int level)
+{
+  if (usb_debug || level)
+    fprintf(stderr, "usb_set_debug: Setting debugging level to %d (%s)\n",
+       level, level ? "on" : "off");
+
+  usb_debug = level;
+}
+
+void usb_init(void)
+{
+  if (getenv("USB_DEBUG"))
+    usb_set_debug(atoi(getenv("USB_DEBUG")));
+
+  usb_os_init();
+}
+
+usb_dev_handle *usb_open(struct usb_device *dev)
+{
+  usb_dev_handle *udev;
+
+  udev = malloc(sizeof(*udev));
+  if (!udev)
+    return NULL;
+
+  udev->fd = -1;
+  udev->device = dev;
+  udev->bus = dev->bus;
+  udev->config = udev->interface = udev->altsetting = -1;
+
+  if (usb_os_open(udev) < 0) {
+    free(udev);
+    return NULL;
+  }
+
+  return udev;
+}
+
+int usb_get_string(usb_dev_handle *dev, int index, int langid, char *buf,
+       size_t buflen)
+{
+  /*
+   * We can't use usb_get_descriptor() because it's lacking the index
+   * parameter. This will be fixed in libusb 1.0
+   */
+  return usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
+                       (USB_DT_STRING << 8) + index, langid, buf, buflen, 1000);
+}
+
+int usb_get_string_simple(usb_dev_handle *dev, int index, char *buf, size_t buflen)
+{
+  char tbuf[255];      /* Some devices choke on size > 255 */
+  int ret, langid, si, di;
+
+  /*
+   * Asking for the zero'th index is special - it returns a string
+   * descriptor that contains all the language IDs supported by the
+   * device. Typically there aren't many - often only one. The
+   * language IDs are 16 bit numbers, and they start at the third byte
+   * in the descriptor. See USB 2.0 specification, section 9.6.7, for
+   * more information on this. */
+  ret = usb_get_string(dev, 0, 0, tbuf, sizeof(tbuf));
+  if (ret < 0)
+    return ret;
+
+  if (ret < 4)
+    return -EIO;
+
+  langid = tbuf[2] | (tbuf[3] << 8);
+
+  ret = usb_get_string(dev, index, langid, tbuf, sizeof(tbuf));
+  if (ret < 0)
+    return ret;
+
+  if (tbuf[1] != USB_DT_STRING)
+    return -EIO;
+
+  if (tbuf[0] > ret)
+    return -EFBIG;
+
+  for (di = 0, si = 2; si < tbuf[0]; si += 2) {
+    if (di >= (buflen - 1))
+      break;
+
+    if (tbuf[si + 1])  /* high byte */
+      buf[di++] = '?';
+    else
+      buf[di++] = tbuf[si];
+  }
+
+  buf[di] = 0;
+
+  return di;
+}
+
+int usb_close(usb_dev_handle *dev)
+{
+  int ret;
+
+  ret = usb_os_close(dev);
+  free(dev);
+
+  return ret;
+}
+
+struct usb_device *usb_device(usb_dev_handle *dev)
+{
+  return dev->device;
+}
+
+void usb_free_dev(struct usb_device *dev)
+{
+  usb_destroy_configuration(dev);
+  free(dev->children);
+  free(dev);
+}
+
+struct usb_bus *usb_get_busses(void)
+{
+  return usb_busses;
+}
+
+void usb_free_bus(struct usb_bus *bus)
+{
+  free(bus);
+}
+
diff --git a/mac/libusb/usb.h b/mac/libusb/usb.h
new file mode 100644 (file)
index 0000000..8e2fedd
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+ * Prototypes, structure definitions and macros.
+ *
+ * Copyright (c) 2000-2003 Johannes Erdfelt <johannes@erdfelt.com>
+ *
+ * This library is covered by the LGPL, read LICENSE for details.
+ *
+ * This file (and only this file) may alternatively be licensed under the
+ * BSD license as well, read LICENSE for details.
+ */
+#ifndef __USB_H__
+#define __USB_H__
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#include <dirent.h>
+
+/*
+ * USB spec information
+ *
+ * This is all stuff grabbed from various USB specs and is pretty much
+ * not subject to change
+ */
+
+/*
+ * Device and/or Interface Class codes
+ */
+#define USB_CLASS_PER_INTERFACE                0       /* for DeviceClass */
+#define USB_CLASS_AUDIO                        1
+#define USB_CLASS_COMM                 2
+#define USB_CLASS_HID                  3
+#define USB_CLASS_PRINTER              7
+#define USB_CLASS_PTP                  6
+#define USB_CLASS_MASS_STORAGE         8
+#define USB_CLASS_HUB                  9
+#define USB_CLASS_DATA                 10
+#define USB_CLASS_VENDOR_SPEC          0xff
+
+/*
+ * Descriptor types
+ */
+#define USB_DT_DEVICE                  0x01
+#define USB_DT_CONFIG                  0x02
+#define USB_DT_STRING                  0x03
+#define USB_DT_INTERFACE               0x04
+#define USB_DT_ENDPOINT                        0x05
+
+#define USB_DT_HID                     0x21
+#define USB_DT_REPORT                  0x22
+#define USB_DT_PHYSICAL                        0x23
+#define USB_DT_HUB                     0x29
+
+/*
+ * Descriptor sizes per descriptor type
+ */
+#define USB_DT_DEVICE_SIZE             18
+#define USB_DT_CONFIG_SIZE             9
+#define USB_DT_INTERFACE_SIZE          9
+#define USB_DT_ENDPOINT_SIZE           7
+#define USB_DT_ENDPOINT_AUDIO_SIZE     9       /* Audio extension */
+#define USB_DT_HUB_NONVAR_SIZE         7
+
+/* All standard descriptors have these 2 fields in common */
+struct usb_descriptor_header {
+       u_int8_t  bLength;
+       u_int8_t  bDescriptorType;
+};
+
+/* String descriptor */
+struct usb_string_descriptor {
+       u_int8_t  bLength;
+       u_int8_t  bDescriptorType;
+       u_int16_t wData[1];
+};
+
+/* HID descriptor */
+struct usb_hid_descriptor {
+       u_int8_t  bLength;
+       u_int8_t  bDescriptorType;
+       u_int16_t bcdHID;
+       u_int8_t  bCountryCode;
+       u_int8_t  bNumDescriptors;
+       /* u_int8_t  bReportDescriptorType; */
+       /* u_int16_t wDescriptorLength; */
+       /* ... */
+};
+
+/* Endpoint descriptor */
+#define USB_MAXENDPOINTS       32
+struct usb_endpoint_descriptor {
+       u_int8_t  bLength;
+       u_int8_t  bDescriptorType;
+       u_int8_t  bEndpointAddress;
+       u_int8_t  bmAttributes;
+       u_int16_t wMaxPacketSize;
+       u_int8_t  bInterval;
+       u_int8_t  bRefresh;
+       u_int8_t  bSynchAddress;
+
+       unsigned char *extra;   /* Extra descriptors */
+       int extralen;
+};
+
+#define USB_ENDPOINT_ADDRESS_MASK      0x0f    /* in bEndpointAddress */
+#define USB_ENDPOINT_DIR_MASK          0x80
+
+#define USB_ENDPOINT_TYPE_MASK         0x03    /* in bmAttributes */
+#define USB_ENDPOINT_TYPE_CONTROL      0
+#define USB_ENDPOINT_TYPE_ISOCHRONOUS  1
+#define USB_ENDPOINT_TYPE_BULK         2
+#define USB_ENDPOINT_TYPE_INTERRUPT    3
+
+/* Interface descriptor */
+#define USB_MAXINTERFACES      32
+struct usb_interface_descriptor {
+       u_int8_t  bLength;
+       u_int8_t  bDescriptorType;
+       u_int8_t  bInterfaceNumber;
+       u_int8_t  bAlternateSetting;
+       u_int8_t  bNumEndpoints;
+       u_int8_t  bInterfaceClass;
+       u_int8_t  bInterfaceSubClass;
+       u_int8_t  bInterfaceProtocol;
+       u_int8_t  iInterface;
+
+       struct usb_endpoint_descriptor *endpoint;
+
+       unsigned char *extra;   /* Extra descriptors */
+       int extralen;
+};
+
+#define USB_MAXALTSETTING      128     /* Hard limit */
+struct usb_interface {
+       struct usb_interface_descriptor *altsetting;
+
+       int num_altsetting;
+};
+
+/* Configuration descriptor information.. */
+#define USB_MAXCONFIG          8
+struct usb_config_descriptor {
+       u_int8_t  bLength;
+       u_int8_t  bDescriptorType;
+       u_int16_t wTotalLength;
+       u_int8_t  bNumInterfaces;
+       u_int8_t  bConfigurationValue;
+       u_int8_t  iConfiguration;
+       u_int8_t  bmAttributes;
+       u_int8_t  MaxPower;
+
+       struct usb_interface *interface;
+
+       unsigned char *extra;   /* Extra descriptors */
+       int extralen;
+};
+
+/* Device descriptor */
+struct usb_device_descriptor {
+       u_int8_t  bLength;
+       u_int8_t  bDescriptorType;
+       u_int16_t bcdUSB;
+       u_int8_t  bDeviceClass;
+       u_int8_t  bDeviceSubClass;
+       u_int8_t  bDeviceProtocol;
+       u_int8_t  bMaxPacketSize0;
+       u_int16_t idVendor;
+       u_int16_t idProduct;
+       u_int16_t bcdDevice;
+       u_int8_t  iManufacturer;
+       u_int8_t  iProduct;
+       u_int8_t  iSerialNumber;
+       u_int8_t  bNumConfigurations;
+};
+
+struct usb_ctrl_setup {
+       u_int8_t  bRequestType;
+       u_int8_t  bRequest;
+       u_int16_t wValue;
+       u_int16_t wIndex;
+       u_int16_t wLength;
+};
+
+/*
+ * Standard requests
+ */
+#define USB_REQ_GET_STATUS             0x00
+#define USB_REQ_CLEAR_FEATURE          0x01
+/* 0x02 is reserved */
+#define USB_REQ_SET_FEATURE            0x03
+/* 0x04 is reserved */
+#define USB_REQ_SET_ADDRESS            0x05
+#define USB_REQ_GET_DESCRIPTOR         0x06
+#define USB_REQ_SET_DESCRIPTOR         0x07
+#define USB_REQ_GET_CONFIGURATION      0x08
+#define USB_REQ_SET_CONFIGURATION      0x09
+#define USB_REQ_GET_INTERFACE          0x0A
+#define USB_REQ_SET_INTERFACE          0x0B
+#define USB_REQ_SYNCH_FRAME            0x0C
+
+#define USB_TYPE_STANDARD              (0x00 << 5)
+#define USB_TYPE_CLASS                 (0x01 << 5)
+#define USB_TYPE_VENDOR                        (0x02 << 5)
+#define USB_TYPE_RESERVED              (0x03 << 5)
+
+#define USB_RECIP_DEVICE               0x00
+#define USB_RECIP_INTERFACE            0x01
+#define USB_RECIP_ENDPOINT             0x02
+#define USB_RECIP_OTHER                        0x03
+
+/*
+ * Various libusb API related stuff
+ */
+
+#define USB_ENDPOINT_IN                        0x80
+#define USB_ENDPOINT_OUT               0x00
+
+/* Error codes */
+#define USB_ERROR_BEGIN                        500000
+
+/*
+ * This is supposed to look weird. This file is generated from autoconf
+ * and I didn't want to make this too complicated.
+ */
+#define USB_LE16_TO_CPU NXSwapLittleShortToHost
+#if 0
+#if 1
+#define USB_LE16_TO_CPU(x) do { x = ((x & 0xff) << 8) | ((x & 0xff00) >> 8); } while(0)
+#else
+#define USB_LE16_TO_CPU(x)
+#endif
+#endif
+
+/* Data types */
+struct usb_device;
+struct usb_bus;
+
+/*
+ * To maintain compatibility with applications already built with libusb,
+ * we must only add entries to the end of this structure. NEVER delete or
+ * move members and only change types if you really know what you're doing.
+ */
+struct usb_device {
+  struct usb_device *next, *prev;
+
+  char filename[PATH_MAX + 1];
+
+  struct usb_bus *bus;
+
+  struct usb_device_descriptor descriptor;
+  struct usb_config_descriptor *config;
+
+  void *dev;           /* Darwin support */
+
+  u_int8_t devnum;
+
+  unsigned char num_children;
+  struct usb_device **children;
+};
+
+struct usb_bus {
+  struct usb_bus *next, *prev;
+
+  char dirname[PATH_MAX + 1];
+
+  struct usb_device *devices;
+  u_int32_t location;
+
+  struct usb_device *root_dev;
+};
+
+struct usb_dev_handle;
+typedef struct usb_dev_handle usb_dev_handle;
+
+/* Variables */
+extern struct usb_bus *usb_busses;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Function prototypes */
+
+/* usb.c */
+usb_dev_handle *usb_open(struct usb_device *dev);
+int usb_close(usb_dev_handle *dev);
+int usb_get_string(usb_dev_handle *dev, int index, int langid, char *buf,
+       size_t buflen);
+int usb_get_string_simple(usb_dev_handle *dev, int index, char *buf,
+       size_t buflen);
+
+/* descriptors.c */
+int usb_get_descriptor_by_endpoint(usb_dev_handle *udev, int ep,
+       unsigned char type, unsigned char index, void *buf, int size);
+int usb_get_descriptor(usb_dev_handle *udev, unsigned char type,
+       unsigned char index, void *buf, int size);
+
+/* <arch>.c */
+int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size,
+       int timeout);
+int usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size,
+       int timeout);
+int usb_interrupt_write(usb_dev_handle *dev, int ep, char *bytes, int size,
+        int timeout);
+int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size,
+        int timeout);
+int usb_control_msg(usb_dev_handle *dev, int requesttype, int request,
+       int value, int index, char *bytes, int size, int timeout);
+int usb_set_configuration(usb_dev_handle *dev, int configuration);
+int usb_claim_interface(usb_dev_handle *dev, int interface);
+int usb_release_interface(usb_dev_handle *dev, int interface);
+int usb_set_altinterface(usb_dev_handle *dev, int alternate);
+int usb_resetep(usb_dev_handle *dev, unsigned int ep);
+int usb_clear_halt(usb_dev_handle *dev, unsigned int ep);
+int usb_reset(usb_dev_handle *dev);
+
+#if 0
+#define LIBUSB_HAS_GET_DRIVER_NP 1
+int usb_get_driver_np(usb_dev_handle *dev, int interface, char *name,
+       unsigned int namelen);
+#define LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP 1
+int usb_detach_kernel_driver_np(usb_dev_handle *dev, int interface);
+#endif
+
+char *usb_strerror(void);
+
+void usb_init(void);
+void usb_set_debug(int level);
+int usb_find_busses(void);
+int usb_find_devices(void);
+struct usb_device *usb_device(usb_dev_handle *dev);
+struct usb_bus *usb_get_busses(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USB_H__ */
diff --git a/mac/libusb/usbi.h b/mac/libusb/usbi.h
new file mode 100644 (file)
index 0000000..5fe8c8e
--- /dev/null
@@ -0,0 +1,74 @@
+#ifndef _USBI_H_
+#define _USBI_H_
+
+#include "usb.h"
+
+#include "error.h"
+
+extern int usb_debug;
+
+/* Some quick and generic macros for the simple kind of lists we use */
+#define LIST_ADD(begin, ent) \
+       do { \
+         if (begin) { \
+           ent->next = begin; \
+           ent->next->prev = ent; \
+         } else \
+           ent->next = NULL; \
+         ent->prev = NULL; \
+         begin = ent; \
+       } while(0)
+
+#define LIST_DEL(begin, ent) \
+       do { \
+         if (ent->prev) \
+           ent->prev->next = ent->next; \
+         else \
+           begin = ent->next; \
+         if (ent->next) \
+           ent->next->prev = ent->prev; \
+         ent->prev = NULL; \
+         ent->next = NULL; \
+       } while (0)
+
+#define DESC_HEADER_LENGTH             2
+#define DEVICE_DESC_LENGTH             18
+#define CONFIG_DESC_LENGTH             9
+#define INTERFACE_DESC_LENGTH          9
+#define ENDPOINT_DESC_LENGTH           7
+#define ENDPOINT_AUDIO_DESC_LENGTH     9
+
+struct usb_dev_handle {
+  int fd;
+
+  struct usb_bus *bus;
+  struct usb_device *device;
+
+  int config;
+  int interface;
+  int altsetting;
+
+  /* Added by RMT so implementations can store other per-open-device data */
+  void *impl_info;
+};
+
+/* descriptors.c */
+int usb_parse_descriptor(unsigned char *source, char *description, void *dest);
+int usb_parse_configuration(struct usb_config_descriptor *config,
+       unsigned char *buffer);
+void usb_fetch_and_parse_descriptors(usb_dev_handle *udev);
+void usb_destroy_configuration(struct usb_device *dev);
+
+/* OS specific routines */
+int usb_os_find_busses(struct usb_bus **busses);
+int usb_os_find_devices(struct usb_bus *bus, struct usb_device **devices);
+int usb_os_determine_children(struct usb_bus *bus);
+void usb_os_init(void);
+int usb_os_open(usb_dev_handle *dev);
+int usb_os_close(usb_dev_handle *dev);
+
+void usb_free_dev(struct usb_device *dev);
+void usb_free_bus(struct usb_bus *bus);
+
+#endif /* _USBI_H_ */
+